﻿using LightCAD.Three;

namespace QdStruct
{
    public class ShearWallAttribute : CptAttribute
    {
        public ShearWallAttribute(string category, string subCategorys) : base(category, subCategorys)
        {

        }
        static ShearWallAttribute()
        {
            CptTypeParamsDef<QdShearWallDef>.ParamsDef = new ParameterSetDefinition { new ParameterDefinition { DataType = LcDataType.String, Name = "MaterialUuid", DisplayName = "材质" } };
        }
        public const string BuiltinUuid = "916ce2a0-3951-4e4b-b5ba-671c2acff77d";
        public override LcComponentDefinition GetBuiltinCpt(string subCategory)
        {
            var typeParams = new LcParameterSet(CptTypeParamsDef<QdShearWallDef>.ParamsDef);
            return new QdShearWallDef(BuiltinUuid, "内置", subCategory, typeParams);
        }
    }
    [ShearWallAttribute("结构墙", "结构墙")]
    public class QdShearWallDef : LcComponentDefinition 
    {
        public QdShearWallDef(string uuid,string name,string subCategory,LcParameterSet typeParams) :base(uuid,name, "结构墙", subCategory, typeParams)
        {
            this.Parameters = new ParameterSetDefinition 
            {
                new ParameterDefinition(){ Name = "Width",DisplayName="墙宽", DataType=LcDataType.Double },
                new ParameterDefinition(){ Name = "Height",DisplayName="墙高", DataType=LcDataType.Double },
                new ParameterDefinition(){ Name = "Bottom",DisplayName="底高度", DataType=LcDataType.Double },
                new ParameterDefinition(){ Name = "CenterOffset",DisplayName="偏移",DataType= LcDataType.Double},
                new ParameterDefinition(){ Name = "IsReverse",DisplayName="翻转",DataType= LcDataType.Bool}
            };
            var mat = MaterialManager.GetMaterial(MaterialManager.ConcreteUuid);
            this.Solid3dProvider = new Solid3dProvider(name) { AssignMaterialsFunc = (c, s) => new LcMaterial[] { mat } };

        }
    }
    public class QdShearWall : DirectComponent
    {
        public Line2d BaseLine
        {
            get
            {

                return (Line2d)this.BaseCurve;
            }
            set
            {
                value.Source = this;
                this.Curves[0].Curve2ds.Clear();
                this.Curves[0].Curve2ds.Add(value);
            }
        }
        //TODO 关于默认值 需要在创建时指定，因为需要根据环境給值
        //public double Width { get; set; }
        //public double Height { get; set; }
        //public double Bottom { get; set; }
        //public double CenterOffset { get; set; }
        //public bool IsReverse { get; set; }
        public override Curve2dGroupCollection Curves { get; set; } = new Curve2dGroupCollection() { new Curve2dGroup() { Curve2ds=new ListEx<Curve2d>()} };

        public double Width
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Width"]);
            }
            set
            {
                this.Parameters["Width"] = value;
            }
        }
        public double Height
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Height"]);
            }
            set
            {
                this.Parameters["Height"] = value;
            }
        }
        public double Bottom
        {
            get
            {
                return Convert.ToDouble(this.Parameters["Bottom"]);
            }
            set
            {
                this.Parameters["Bottom"] = value;
            }
        }

        public double CenterOffset
        {
            get
            {
                return Convert.ToDouble(this.Parameters["CenterOffset"]);
            }
            set
            {
                this.Parameters["CenterOffset"] = value;
            }
        }
        public bool IsReverse
        {
            get
            {
                return Convert.ToBoolean(this.Parameters["IsReverse"]);
            }
            set
            {
                this.Parameters["IsReverse"] = value;
            }
        }
        public QdShearWall(QdShearWallDef wallDef):base(wallDef)
        {
            this.Type = StructElementType.ShearWall;
        }
        public static List<Line2d> GetShapeCurves(Line2d line, double width)
        {

            double x1 = line.Start.X;
            double y1 = line.Start.Y;
            double x2 = line.End.X;
            double y2 = line.End.Y;
            double setoff = (width) / 2;
            Vector2 p1=new Vector2();
            Vector2 p2=new Vector2();
            Vector2 p3=new Vector2();
            Vector2 p4=new Vector2();

            if (x1 == x2)
            {
                p1.Y = y1;
                p1.X = x1 + setoff;
                p2.Y = y1;
                p2.X = x1 - setoff;
                p3.Y = y2;
                p3.X = x2 - setoff;
                p4.Y = y2;
                p4.X = x2 + setoff;
            }
            else
            if (y1 == y2)
            {
                p1.Y = y1 + setoff;
                p1.X = x1;
                p2.Y = y1 - setoff;
                p2.X = x1;
                p3.Y = y2 - setoff;
                p3.X = x2;
                p4.Y = y2 + setoff;
                p4.X = x2;
            }
            else
            {
                double k = (y2 - y1) / (x2 - x1);
                double k1 = -1 / k;
                double b1 = y1 - k1 * x1;



                double xA = x1;
                double yA = y1;
                double xB = x1 + Math.Pow(width, 2);
                double yB = k1 * xB + b1;

                // 给定距离
                double distance = setoff;

                // 计算线段的方向向量
                double directionX = xB - xA;
                double directionY = yB - yA;

                // 计算方向向量的模长
                double length = Math.Sqrt(directionX * directionX + directionY * directionY);

                // 标准化方向向量（单位化）
                double unitDirectionX = directionX / length;
                double unitDirectionY = directionY / length;

                // 计算目标点的坐标
                p1.X = xA + distance * unitDirectionX;
                p1.Y = yA + distance * unitDirectionY;


                Matrix3 matrix3 = Matrix3.GetMove(p1, line.Start);
                p2 = matrix3.MultiplyPoint(line.Start);

                matrix3 = Matrix3.GetMove(line.Start, line.End);

                p3 = matrix3.MultiplyPoint(p2);
                p4 = matrix3.MultiplyPoint(p1);
 

            }

            List<Line2d> line2Ds = new List<Line2d>();
            Line2d line2D = new Line2d();
            line2D.Start = p1;
            line2D.End = p2;

            line2Ds.Add(line2D);
            line2D = new Line2d();
            line2D.Start = p2;
            line2D.End = p3;

            line2Ds.Add(line2D);
            line2D = new Line2d();
            line2D.Start = p3;
            line2D.End = p4;

            line2Ds.Add(line2D);
            line2D = new Line2d();
            line2D.Start = p4;
            line2D.End = p1;

            line2Ds.Add(line2D);
            return line2Ds;
        }
        public void set()
        {
            //var args = new PropertyChangedEventArgs
            //{
            //    Object = this,
            //    PropertyName = "",
            //    OldValue = null,
            //    NewValue = null,
            //};
            //this.PropertyChangedAfter(args);
            //this.PropertyChangedAfter?.Invoke(this, args);
            //this.docRt.Document.OnPropertyChangedAfter(args);
            ////RestShearWalls(qdShearWall);
        }
        public void CreateShapeCurves()
        {
            this.Points.Clear();
            this.Curves.Clear();
            List<Line2d> line2Ds = GetShapeCurves(this.BaseLine, this.Width);
            this.Points.Add(line2Ds[1].Start);
            this.Points.Add(line2Ds[1].End);
            this.Points.Add(line2Ds[3].Start);
            this.Points.Add(line2Ds[3].End);
            Curve2dGroup crGrp = null;
            if (this.Curves.Count == 0)
            {
                this.Curves.Add(new Curve2dGroup { Curve2ds = new ListEx<Curve2d>() });
            }
            crGrp = this.Curves[0];
            crGrp.Curve2ds.AddRange(line2Ds.Cast<Curve2d>());
        }
        public  void ResetShapeCurves()
        {
            CreateShapeCurves();
            //List<Line2d> line2Ds =
            //GetShapeCurves(this.BaseLine, this.Width);
            //this.Points.Add(line2Ds[1].Start);
            //this.Points.Add(line2Ds[1].End);
            //this.Points.Add(line2Ds[3].Start);
            //this.Points.Add(line2Ds[3].End);
            //this.Curves.AddRange(line2Ds);



        }
  

        public override LcElement ApplyMatrix(Matrix3 matrix)
        {
            BaseLine.Start = matrix.MultiplyPoint(BaseLine.Start);
            BaseLine.End = matrix.MultiplyPoint(BaseLine.End);
            ResetShapeCurves();
            return this;
        }

        public override LcElement Clone()
        {
            var clone = new QdShearWall(this.Definition as QdShearWallDef);
            clone.Copy(this);
            clone.Initilize(this.Document);
            return clone;

        }

        public override void Copy(LcElement src)
        {
            base.Copy(src);
            var wall = ((QdShearWall)src);
            this.BaseLine = wall.BaseLine.Clone() as Line2d;
        }

        public void Set(Vector2 start = null, Vector2 end = null, bool fireChangedEvent = true)
        {
            //PropertySetter:Start,End
            if (!fireChangedEvent)
            {
                if (start != null) BaseLine.Start = start;
                if (end != null) BaseLine.End = end;
            }
            else
            {
                bool chg_start = (start != null && start != BaseLine.Start);
                bool chg_end = (end != null && end != BaseLine.End);
                if (!chg_start && !chg_end)
                    return;
                var old = BaseLine.Clone();
                OnPropertyChangedBefore(nameof(BaseLine), BaseLine, null);
                if (chg_start)
                {
                    OnPropertyChangedBefore(nameof(BaseLine.Start), BaseLine.Start, start);
                    var oldValue = BaseLine.Start;
                    BaseLine.Start = start;
                }
                if (chg_end)
                {
                    var oldValue = BaseLine.End;
                    BaseLine.End = end;
                }
                this.ResetCache();
                OnPropertyChangedAfter(nameof(BaseLine.Start), old, BaseLine);
            }
        }

        protected override void OnPropertyChanged(string propertyName, LcPropertyGroup extPropGroup, LcProperty extProp)
        {
            base.OnPropertyChanged(propertyName, extPropGroup, extProp);
            ResetShapeCurves();
        }
        public override Box2 GetBoundingBox()
        {
            return new Box2().SetFromPoints(BaseLine.Start, BaseLine.End);
        }
        public override Box2 GetBoundingBox(Matrix3 matrix)
        {
            return new Box2().SetFromPoints(matrix.MultiplyPoint(BaseLine.Start), matrix.MultiplyPoint(BaseLine.End));
        }
        public override bool IntersectWithBox(Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                //如果元素盒子，与多边形盒子不相交，那就可能不相交
                return false;
            }
            return GeoUtils.IsPolygonIntersectLine(testPoly.Points, BaseLine.Start, BaseLine.End)
                || GeoUtils.IsPolygonContainsLine(testPoly.Points, BaseLine.Start, BaseLine.End);
        }

        public override bool IncludedByBox(Polygon2d testPoly, List<RefChildElement> includedChildren = null)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                return false;
            }
            return GeoUtils.IsPolygonContainsLine(testPoly.Points, BaseLine.Start, BaseLine.End);
        }

        public override void Translate(double dx, double dy)
        {
            var ts = new Vector2(BaseLine.Start.X + dx, BaseLine.Start.Y + dy);
            var te = new Vector2(BaseLine.End.X + dx, BaseLine.End.Y + dy);
            Set(ts, te);
            ResetBoundingBox();
            ResetShapeCurves();

        }
        public override void Move(Vector2 startPoint, Vector2 endPoint)
        {
            Matrix3 matrix3 = Matrix3.GetMove(startPoint, endPoint);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void Scale(Vector2 basePoint, double scaleFactor)
        {
            Matrix3 matrix3 = Matrix3.GetScale(scaleFactor, basePoint);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void Scale(Vector2 basePoint, Vector2 scaleVector)
        {

            Matrix3 matrix3 = Matrix3.GetScale(scaleVector, basePoint);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void Rotate(Vector2 basePoint, double rotateAngle)
        {
            Matrix3 matrix3 = Matrix3.RotateInRadian(rotateAngle, basePoint);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void Mirror(Vector2 axisStart, Vector2 axisEnd)
        {
            Matrix3 matrix3 = Matrix3.GetMirror(axisEnd, axisStart);
            this.Set(matrix3.MultiplyPoint(BaseLine.Start), matrix3.MultiplyPoint(BaseLine.End));
            ResetBoundingBox();
            ResetShapeCurves();
        }
        public override void ResetCache()
        {
            base.ResetCache();
            this.ResetShapeCurves();
        }
        public override void WriteProperties(Utf8JsonWriter writer, JsonSerializerOptions soptions)
        {
            base.WriteProperties(writer, soptions);
        }
        public override void ReadProperties(ref JsonElement jele)
        {
            base.ReadProperties(ref jele);

            this.BaseLine = jele.ReadCurve2dProperty(nameof(this.BaseCurve)) as Line2d;
            this.CreateShapeCurves();
        }
    }
}